// wtkdisplay.cpp
//

#include "config.h"
#include "wtk/wtkdisplay.hpp"
#include "wtk/wtkapplication.hpp"
#include "wtk/wtkwidget.hpp"

using namespace wtk;



// Display::Display
//
Display::Display ( Application &application,
                   const wgl::WindowSettings &settings )
  : application(application),
    wgl_window(settings, false),
    root_widget(*this),
    font(new wgl::Font(std::string(WTK_DATADIR) + "/fonts/FreeMonoBold.ttf", 18))
{
  root_widget.set_layout(root_layout);
  open(); // [FIXME] (crash if not open immediately)
}



// Display::Display
//
Display::Display ( const wgl::WindowSettings &settings )
  : Display(Application::get_current_application(),
            settings)
{
}



// Display::Display
//
Display::Display ( int width,
                   int height )
  : Display(wgl::WindowSettings
            {
              width,
              height,
              false, // fullscreen
              false, // fullscreen_desktpo
              true                 
            })
{
}



// Display::~Display
//
Display::~Display ()
{
  close();
}



// Display::open
//
bool Display::open ()
{
  if (is_open())
    return true;

  WTK_TRACE("opening display");

  if (!wgl_window.show())
    {
      WTK_FATAL("could not open wgl window");
      return false;
    }
  //
  application.register_display(*this);
  
  // [FIXME] root layout handling is not good
  int real_width, real_height;
  wgl_window.get_real_size(real_width, real_height);
  WTK_TRACE("display real size: %dx%d", real_width, real_height);
  root_layout.set_root_size(real_width, real_height);
  root_widget.size_allocate({0, 0, real_width, real_height});
  root_widget.show();
  
  return true;
}



// Display::close
//
void Display::close ()
{
  if (!is_open())
    return;
  
  WTK_TRACE("closing display");

  root_widget.hide();
  application.unregister_display(*this);
  wgl_window.hide();
}



// Display::set_top_widget_layout
//
void Display::set_top_widget_layout ( Widget &widget,
                                      bool fullscreen )
{
  root_layout.set_child_properties(widget, fullscreen);
  widget.queue_resize();
}



// Display::set_focus_widget
//
void Display::set_focus_widget ( Widget *widget )
{
  // [TODO] handle ownership if widget is destroyed
  WTK_ASSERT(widget->get_display() == this);
  focus_widget = widget;
}



// Display::update
//
void Display::update ()
{
  // pair<dtime, fps>
  FPSInfo fps_info;
  fps_counter.step(fps_info);
  
  if (root_widget.needs_resize())
    {
      root_layout.process_resize();
      root_widget.flags.reset(WidgetFlagsBit::bNeedsResize);
    }

  // WTK_TRACE("display=%s (%dx%d), gl=%s", WTK_DEBUG_NAME(this), width, height, WTK_DEBUG_NAME(&gl));

  wgl_window.make_current();

  root_widget.process_redraw();

  { // print fps
    int rw, rh, tw, th;
    get_real_size(rw, rh);
    font->get_text_size("XXXXXXXXX", tw, th);
    char text[64];
    std::snprintf(text, 64, "%.1fFPS", fps_info.fps);

    gl.Viewport(0, 0, rw, rh);
    gl.MatrixMode(GL_PROJECTION);
    gl.LoadIdentity();
    gl.Ortho(0.f, GLfloat(rw), 0.f, GLfloat(rh), -1.f, 1.f);
    gl.MatrixMode(GL_MODELVIEW);
    gl.LoadIdentity();
    // bg
    gl.Begin(GL_QUADS);
    gl.Color3f(1.f, 1.f, 1.f);
    gl.Vertex2f(rw - tw - 4, th + 4);
    gl.Vertex2f(rw - 4, th + 4);
    gl.Vertex2f(rw - 4, 4.f);
    gl.Vertex2f(rw - tw - 4, 4.f);
    gl.End();
    // text
    font->render_text_image(text, GLfloat(rw - tw - 4), 4.f - font->get_scaled_descent());
  }

  // On macOS, make sure you bind 0 to the draw framebuffer before
  // swapping the window, otherwise nothing will happen. If you aren't
  // using glBindFramebuffer(), this is the default and you won't have
  // to do anything extra.
  wgl_window.swap_display();
}



// Display::get_widget_at
//
Widget *Display::get_widget_at ( int x,
                                 int y,
                                 int *rx,
                                 int *ry )
{
  return root_widget.get_child_at(x, y, rx, ry);
}
